/**********************************
c file for module 3!
1. Create five PCBs, and initialize them as described in 
the previous section. These PCBs are linked to the five 
test procedures.
2. Insert all five PCBs on the ready queue.
3. Link the int 60h interrupt to your system call handler 
using the support procedure sys_set_vec (described below). 
Note that sys_exit will restore this vector to its original 
value.
4. Call your dispatcher to begin execution.
**********************************/

#ifndef r3_h
#include <dos.h>
#include <stdlib.h>
#include <stdio.h>
#include "mpx_supt.h"
#include "R2.H"
#include "R1.H"
#include "r3.h"
#include "commhand.h"
#include "procs-r3.h"
#endif

/**********************************
CONSTANTS!

**********************************/
#define SYS_STACK_SIZE  1024
#define IDLE 0
#define EXITS 2
#define RUNNING 1
#define FIFO 0

unsigned short ss_save;
unsigned short sp_save;
unsigned short new_ss;
unsigned short new_sp;
unsigned short old_ss;
unsigned short old_sp;

PCB* cop;
char sys_stack[SYS_STACK_SIZE];
params *param_ptr;

/**********************************
Functions!

**********************************/
int dispatch_init() 
{
    sys_set_vec(&sys_call);
    cop = NULL;
    return 0;
}

void interrupt sys_call()
{
    old_ss = _SS;
    old_sp = _SP;
    new_ss = FP_SEG(&sys_stack);
    new_sp = FP_OFF(&sys_stack) + SYS_STACK_SIZE;
	_SS = new_ss;
	_SP = new_sp;
	cop->top = (unsigned char *) MK_FP( old_ss, old_sp);
	param_ptr = (params*)(cop->top + sizeof(contextPtr));
	
	if (param_ptr -> op_code == IDLE)
	{
		cop->states = READY;
		insertPCB(cop, getReadyQueue(), FIFO);
	}
	if (param_ptr -> op_code == EXITS)
	{
		removePCB(cop); 
		cop = NULL;
	}

	//_SS = old_ss;
	//_SP = old_sp;
	dispatch();
}

void interrupt dispatch()
{
	if (ss_save == NULL)
	{
		ss_save = _SS;
		sp_save = _SP;
	}
	cop = getReadyQueue()->head;
	if (getReadyQueue()->head != NULL) 
	{
        helperRemove(cop);
        cop->states = RUNNING;
        new_ss = FP_SEG(cop->top);
		new_sp = FP_OFF(cop->top);
		_SS = new_ss;
		_SP = new_sp;
	}
	else 
	{
        cop = NULL;
        _SS = ss_save;
        _SP = sp_save;
		ss_save = NULL;
		sp_save = NULL;
    }
	//test1_R3();
}

int loadprocs(int argc, char *argv[])
{
	context *proc1_context;
	context *proc2_context;
	context *proc3_context;
	context *proc4_context;
	context *proc5_context;
	PCB* proc1;
	PCB* proc2;
	PCB* proc3;
	PCB* proc4;
	PCB* proc5;
	proc1 = allocatePCB();
	proc2 = allocatePCB();
	proc3 = allocatePCB();
	proc4 = allocatePCB();
	proc5 = allocatePCB();
	if(strcmp(argv[0], "loadprocs") != 0)
		return 0;
	else if(argc != 1)
	{
		printf("Invalid loadprocs command\n");
		return 1;
	}
	else {
		if (findPCB("test1") != NULL) 
		{
			printf("Test Process 1 already loaded\n");
		}
		else 
		{
			strcpy(proc1->name, "test1");
			proc1->classs = 1;
			proc1->priority = 20;
			proc1_context = (context*)proc1->top;
			proc1_context->IP = FP_OFF(&test1_R3);
			proc1_context->CS = FP_SEG(&test1_R3);
			proc1_context->FLAGS = 0x200;
			proc1_context->DS = _DS;
			proc1_context->ES = _ES;
			insertPCB(proc1,getReadyQueue(),1);
		}
		/*
		if (findPCB("test2")) 
		{
			printf("Test Process 2 already loaded\n");
		}
		else 
		{
			strcpy(proc2->name, "test2");
			proc2->classs = 1;
			proc2->priority = 20;
			proc2_context = (context*)proc2->top;
			proc2_context->IP = FP_OFF(&test2_R3);
			proc2_context->CS = FP_SEG(&test2_R3);
			proc2_context->FLAGS = 0x200;
			proc2_context->DS = _DS;
			proc2_context->ES = _ES;
			insertPCB(proc2,getReadyQueue(),1);
		}
		if (findPCB("test3")) 
		{	
			printf("Test Process 3 already loaded\n");
		}
		else 
		{
			strcpy(proc3->name, "test3");
			proc3->classs = 1;
			proc3->priority = 20;
			proc3_context = (context*)proc3->top;
			proc3_context->IP = FP_OFF(&test3_R3);
			proc3_context->CS = FP_SEG(&test3_R3);
			proc3_context->FLAGS = 0x200;
			proc3_context->DS = _DS;
			proc3_context->ES = _ES;
			insertPCB(proc3,getReadyQueue(),1);
		}
		if (findPCB("test4")) 
		{	
			printf("Test Process 4 already loaded\n");
		}
		else 
		{
			strcpy(proc4->name, "test4");
			proc4->classs = 1;
			proc4->priority = 20;
			proc4_context = (context*)proc4->top;
			proc4_context->IP = FP_OFF(&test4_R3);
			proc4_context->CS = FP_SEG(&test4_R3);
			proc4_context->FLAGS = 0x200;
			proc4_context->DS = _DS;
			proc4_context->ES = _ES;
			insertPCB(proc4,getReadyQueue(),1);
		}
		if (findPCB("test5")) 
		{
			printf("Test Process 3 already loaded\n");
		}
		else 
		{
			strcpy(proc5->name, "test5");
			proc5->classs = 1;
			proc5->priority = 20;
			proc5_context = (context*)proc5->top;
			proc5_context->IP = FP_OFF(&test5_R3);
			proc5_context->CS = FP_SEG(&test5_R3);
			proc5_context->FLAGS = 0x200;
			proc5_context->DS = _DS;
			proc5_context->ES = _ES;
			insertPCB(proc5,getReadyQueue(),1);
		}
		*/
		return 1;
	}
}

int dispatching( int argc, char *argv[] )
{
	if(strcmp(argv[0], "dispatching") != 0)
	{
		return 0;
	}
	else if( argc != 1 )
	{
		printf( "invalid dispatch call");
		return 1;
	}
	else
	{
		dispatch();
		return 1;
	}
}